﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Diagnostics;
using DynORM.Interfaces.BLLMapper.Enum;
using DynORM.Enums;
using DynORM.BLLMapper;
using DynORM.Interfaces;
using DynORM.Mappers;
using DynORM.ReferenceObjects;

namespace UnitTestProject
{
    [TestClass]
    public class BLLAdaptiveMapperManyToManyUnitTests_Oracle
    {
        #region db creation and clean up
        //these two members are used only in CreateDB and DropDB methods
        //production code and test methods take this setting from the config file
        const DBMSTypes dbType = DBMSTypes.Oracle;
        static string dbName = "TestDB";
        static string syspwd = "123";
        static string userpwd = "123";
        static string pooling = "Pooling=false;";//otherwise it won't let drop db (db will be in use with connections in pool)
        static string connectionStringToDatabase = String.Format("User Id={0}; Password={1}; Data Source=XE;{2}", dbName, userpwd, pooling);
        static string connectionStringToServer = String.Format("User Id=SYS; Password={0}; Data Source=XE; DBA Privilege=SYSDBA;{1}", syspwd, pooling);

        [TestInitialize]
        public void TestInit()
        {
            IORMDatabase database = new Database(dbName);
            database.AuxDatas.Add(userpwd);
            database.AuxDatas.Add(syspwd);
            DatabaseMapper.CreateDatabase(connectionStringToServer, dbType, database, true, false);
        }

        [TestCleanup]
        public void TestClean()
        {
            DatabaseMapper.DropDatabase(connectionStringToServer, dbType, dbName, new string[] { userpwd, syspwd });
        }

        #endregion

        //it's important to give tables short names cause some RDBMSes limits the length of the names (in Oracle this limit is 30 characters). this become even more important taking into account that link entities names compound using tables' names that they link 
        [TableAttribute(TableName = "Ent1")]
        [ForeignKeyDeclarationAttribute(typeof(TestBLL2), RelationQuantity.ManyOrZeroToManyOrZero, "RelatedBLLObjs1", 0)]
        public class TestBLL1 : BLLSuperType
        {
            [PrimaryKeyAttribute("RowID", 0)]
            public Guid ID { get; set; }

            [FieldAttribute(FieldName = "SomeField1")]
            public int SomeProperty1 { get; set; }

            [FieldAttribute]
            public string SomeProperty2 { get; set; }

            private List<TestBLL2> relatedBLLObjs = new List<TestBLL2>();
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public List<TestBLL2> RelatedBLLObjs1
            {
                get
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    return this.relatedBLLObjs;
                }
                set
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    this.relatedBLLObjs = value;
                }
            }
        }

        [TableAttribute(TableName = "Ent2")]
        [ForeignKeyDeclarationAttribute(typeof(TestBLL1), RelationQuantity.ManyOrZeroToManyOrZero, "RelatedBLLObjs2", 0)]
        public class TestBLL2 : BLLSuperType
        {
            [PrimaryKeyAttribute("RowID", 0)]
            public Guid ID { get; set; }

            [FieldAttribute(FieldName = "SomeField3")]
            public int SomeProperty3 { get; set; }

            [FieldAttribute]
            public string SomeProperty4 { get; set; }

            private List<TestBLL1> relatedBLLObjs = new List<TestBLL1>();
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public List<TestBLL1> RelatedBLLObjs2
            {
                get
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    return this.relatedBLLObjs;
                }
                set
                {
                    Load(new BLLAdaptiveMapper(connectionStringToDatabase, dbType));
                    this.relatedBLLObjs = value;
                }
            }
        }


        [TestMethod]
        public void SaveBLLObjTestParentChildManyToMany()
        {
            IBLLAdaptiveMapper mapper = new BLLAdaptiveMapper(connectionStringToDatabase, dbType);
            Guid id2 = Guid.NewGuid();
            TestBLL2 bllObj2 = (TestBLL2)mapper.Create(typeof(TestBLL2), id2);
            bllObj2.SomeProperty3 = 5;
            bllObj2.SomeProperty4 = "9";
            bllObj2.MarkAsLoaded();

            Guid id1 = Guid.NewGuid();
            TestBLL1 bllObj1 = (TestBLL1)mapper.Create(typeof(TestBLL1), id1);
            bllObj1.SomeProperty1 = 15;
            bllObj1.SomeProperty2 = "19";
            bllObj1.MarkAsLoaded();
            bllObj1.RelatedBLLObjs1.Add(bllObj2);

            bllObj2.RelatedBLLObjs2.Add(bllObj1);

            mapper.Write(bllObj2, true);

            mapper.Write(bllObj1, true);

            //mapper.DeleteDeep(bllObj1);
            mapper.DeleteCascade(bllObj2);
            mapper.DeleteCascade(bllObj1);
        }

        [TestMethod]
        public void ReadBLLObjTestParentChildManyToMany()
        {
            IBLLAdaptiveMapper mapper = new BLLAdaptiveMapper(connectionStringToDatabase, dbType);
            Guid id2 = Guid.NewGuid();
            TestBLL2 bllObj2 = (TestBLL2)mapper.Create(typeof(TestBLL2), id2);
            bllObj2.SomeProperty3 = 5;
            bllObj2.SomeProperty4 = "9";
            bllObj2.MarkAsLoaded();

            Guid id1 = Guid.NewGuid();
            TestBLL1 bllObj1 = (TestBLL1)mapper.Create(typeof(TestBLL1), id1);
            bllObj1.SomeProperty1 = 15;
            bllObj1.SomeProperty2 = "19";
            bllObj1.MarkAsLoaded();
            bllObj1.RelatedBLLObjs1.Add(bllObj2);

            bllObj2.RelatedBLLObjs2.Add(bllObj1);

            mapper.Write(bllObj2, true);
            mapper.Write(bllObj1, true);

            TestBLL2 retrievedBLLObj2 = (TestBLL2)mapper.Read(typeof(TestBLL2), id2);
            Assert.AreEqual<int>(bllObj2.SomeProperty3, retrievedBLLObj2.SomeProperty3);
            Assert.AreEqual<string>(bllObj2.SomeProperty4, retrievedBLLObj2.SomeProperty4);
            Assert.AreEqual<int>(bllObj2.RelatedBLLObjs2[0].SomeProperty1, retrievedBLLObj2.RelatedBLLObjs2[0].SomeProperty1);
            Assert.AreEqual<string>(bllObj2.RelatedBLLObjs2[0].SomeProperty2, retrievedBLLObj2.RelatedBLLObjs2[0].SomeProperty2);

            TestBLL1 retrievedBLLObj1 = (TestBLL1)mapper.Read(typeof(TestBLL1), id1);
            Assert.AreEqual<int>(bllObj1.SomeProperty1, retrievedBLLObj1.SomeProperty1);
            Assert.AreEqual<string>(bllObj1.SomeProperty2, retrievedBLLObj1.SomeProperty2);
            Assert.AreEqual<int>(bllObj1.RelatedBLLObjs1[0].SomeProperty3, retrievedBLLObj1.RelatedBLLObjs1[0].SomeProperty3);
            Assert.AreEqual<string>(bllObj1.RelatedBLLObjs1[0].SomeProperty4, retrievedBLLObj1.RelatedBLLObjs1[0].SomeProperty4);

            //mapper.DeleteDeep(bllObj1);
            mapper.DeleteCascade(bllObj2);
            mapper.DeleteCascade(bllObj1);
        }


    }
}
